#include "CalibrationSensor.h"
#include <math.h>
#include "USART_HMI.h"
#include "ReadSenser.h"

// 本文件用于更新压力目标点，辅助进行闭环

// 五个测量点
typedef struct _FiveMeasurePoint_s
{
    float point0;
    float point1;
    float point2;
    float point3;
    float point4;
} FiveMeasurePoint_s;

// 六个测量点
typedef struct _SixMeasurePoint_s
{
    float point0;
    float point1;
    float point2;
    float point3;
    float point4;
    float point5;
} SixMeasurePoint_s;

// 一个测量点
typedef struct _OneMeasurePoint_s
{
    float point0;
} OneMeasurePoint_s;

// 共用
typedef union _MeasurePoint_u
{
    FiveMeasurePoint_s five;
    SixMeasurePoint_s six;
    OneMeasurePoint_s one;
    float array[6];
} MeasurePoint_u;

// 传感器类型
typedef enum _SensorType_e
{
    NoneSensor = 0x00,
    GY_57 = 0x01,
    GY_58 = 0x02,
    GYY_8,  // 6
    GY4_1A, // 6
    GY8_2,  // 5

    XY0_18_1B = 0x11,
    XY0_15_1,
    XY0_65_1,
    XY2_5_B1,
    XY3_5_2,
    XY12_5_B1,
} SensorType_e;

typedef struct _SensorStr_s
{
    SensorType_e type;
    MeasurePoint_u point;
} SensorStr_s;

// 传感器类型到传感器编号的转换表
__attribute__((section(".data"))) const uint8_t SensorType2SensorIndexTranslateList[] = {0, 0, 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                                                         0, 5, 6, 7, 8, 9, 10};

// 传感器编号到传感器测量点数的转换表
__attribute__((section(".data"))) const uint8_t SensorIndex2MeasurePointTranslateList[] = {5, 5, 6, 6, 5, 1, 1, 1, 1, 1, 1};

// 标准表
__attribute__((section(".data"))) const SensorStr_s StandardSensorList[] = {
    {.type = GY_57, .point.five = {0, 2, 4, 6, 8}},
    {.type = GY_58, .point.five = {0, 1, 2, 3, 4}},
    {.type = GYY_8, .point.six = {0, 1, 2, 3, 4, 5}},
    {.type = GY4_1A, .point.six = {0, 0.8, 1.6, 2.4, 3.2, 4.0}},
    {.type = GY8_2, .point.five = {0, 1.55, 4, 6.5, 8}},
    {.type = XY0_18_1B, .point.one = {0.18}},
    {.type = XY0_15_1, .point.one = {0.15}},
    {.type = XY0_65_1, .point.one = {0.65}},
    {.type = XY2_5_B1, .point.one = {2.5}},
    {.type = XY3_5_2, .point.one = {3.5}},
    {.type = XY12_5_B1, .point.one = {12.5}},
};

// 当前的表
SensorStr_s CurrentSensor = {0};
// 当前的目标压力
float CurrentTargetPressure = 0;
// 最小误差
float MinDelta = 0.01;

// 回调函数指针，类似委托调用
typedef void (*CalibrationTargetCallback)(float);
uint8_t CalibrationTargetCallbackCount = 0;
CalibrationTargetCallback CallbackList[6] = {};

// 完成一次的回调
void FinishedCallback(uint8_t index, uint8_t press)
{
    // HMIMeasureFinish();
    // 正常仪表不需要特殊回调
    // 回调默认放在返回值中
}

/**
 * @brief 更新的回调
 *
 * @param index
 * @param level
 */
void RaisePressureLevelCallback(uint8_t index, uint8_t level)
{
    // 更新
    CurrentTargetPressure = StandardSensorList[index].point.array[level];
}

float GetCurrentTargetPressure(void)
{
    return CurrentTargetPressure;
}

/**
 * @brief 判断是否能进入下一阶段，也就是是否可以更新压力值
 *
 * @param press
 * @return uint8_t
 */
uint8_t PressureUpdateJudge(uint8_t index, uint8_t level)
{
    static uint8_t count = 0;
    if (++count > 30) // 定时
    {
        // 定时三秒完成，认为数值稳定
        count = 0;
        CurrentSensor.point.array[level] = ReadADCData_float();
        HMISetMeasureVoltage(level, ReadADCData_float());
        return 1;
    }
    return 0;
}

uint8_t IsSwitchInstrument(SensorStr_s sensor)
{
    if (sensor.type & 0x10)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

/**
 * @brief Get the Current Instrument Kp Param object
 *
 * @note 目的是为了在测量通断型仪表时减速
 * @return float
 */
float GetCurrentInstrumentKpParam(void)
{
    if (IsSwitchInstrument(CurrentSensor))
    {
        return 0.5;
    }
    else
    {
        return 1.0;
    }
}

/**
 * @brief Set the Current Sensor Type object
 *
 * @param index
 */
void SetCurrentSensorType(uint8_t index)
{
    if (index < 0x17 && (index > 0x10 || index < 0x06)) // 处于有效值
    {
        CurrentSensor.type = (SensorType_e)index;
        CurrentTargetPressure = 0; // 清空
    }
}

/**
 * @brief 更新压力值，在每次读取到压力时调用。压力读取为定时读取，所以这个函数的执行也有固定时间
 * @brief 也可以在控制器内调用
 * @note 目标压力会自动更新，更新完毕后会自动清零，当到达一次目标压力后会触发一次回调，回调的参数带有当前压力值，此时可将当前电压值发送至HMI中
 *
 * @param press
 * @return uint8_t 完成返回0，未完成返回1
 */
uint8_t UpdatePressure(float press)
{
    uint8_t index = SensorType2SensorIndexTranslateList[CurrentSensor.type];
    static uint8_t i = 0;

    if (HMIGetStatus() == HMI_Manual)
    {
        // 手动模式，判断压力是否到达目标值
        if (fabsf(press - HMIGetData()) < MinDelta)
        {
            // 已找到当前压力点，即为变化点，结束
            if (++i > 30) // 定时
            {
                i = 0;
                CurrentTargetPressure = 0;
                FinishedCallback(index, press);
                return 0;
            }
        }
        return 1;
    }
    else
    { // 第一次进入进行初始赋值
        if (CurrentTargetPressure == 0)
        {
            i = 0;
            if (IsSwitchInstrument(CurrentSensor))
            {
                CurrentTargetPressure = 1.2 * StandardSensorList[index].point.array[0]; // 若为通断型仪表，加到1.2倍压力
            }
            else
            {
                CurrentTargetPressure = StandardSensorList[index].point.array[0]; // 默认赋值第一个
            }
        }
        // 先检测是否是通断型仪表
        if (IsSwitchInstrument(CurrentSensor))
        {
            // 若为通断型仪表则检测电压是否大于4V
            if (ReadADCData_float() > 4)
            {
                // 已找到当前压力点，即为变化点，结束
                HMISetMeasureVoltage(i, press);
                i = 0;
                CurrentTargetPressure = 0;
                FinishedCallback(index, press);
                return 0;
            }
        }
        // 由于大部分表的第一个测量点都为0，在初始赋值后直接检测即可
        // 若符合要求即可更新
        if (fabsf(press - CurrentTargetPressure) < MinDelta)
        {
            // 误差小于给定值，认为已经达到目标压力
            if (PressureUpdateJudge(index, i)) // 只有数值稳定后才能进行下一阶段
            {
                for (; i < SensorIndex2MeasurePointTranslateList[index]; i++)
                {
                    if (StandardSensorList[index].point.array[i] > CurrentTargetPressure)
                    {
                        // 找到更大的目标压力，向上更新
                        RaisePressureLevelCallback(index, i);
                        return 1;
                    }
                }
                // 循环完依旧没有找到，则该仪表已达最大压力，结束
                i = 0;
                CurrentTargetPressure = 0;
                FinishedCallback(index, press);
                return 0;
            }
        }
        return 1;
    }
    return 1;
}
